/*
 * Мосты
 */
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <assert.h>
#include <string.h>
#include <limits.h>

#ifdef D
# define debug_fprintf(x)	fprintf x
#else
# define debug_fprintf(x)	((void) 0)
#endif

#define MIN(a, b)	((a) < (b) ? (a) : (b))

/* {{{ memory allocation wrappers */
extern void *s_calloc(size_t n, size_t size)
{
	void *ptr;
	ptr = calloc(n, size);
	assert(ptr != NULL);
	if (ptr == NULL) {
		debug_fprintf((stderr, "out of memory\n"));
	}
	return ptr;
}

extern void *s_malloc(size_t size)
{
	void *ptr;
	ptr = malloc(size);
	assert(ptr != NULL);
	if (ptr == NULL) {
		debug_fprintf((stderr, "out of memory\n"));
	}
	return ptr;
}
/* }}} */

/* {{{ autoarray */
struct vector {
	int *data;
	int n;
	int max;
};
/* {{{ functions */
extern int
vector_init(struct vector *v, int p)
{
	if (v == NULL) {
		fprintf(stderr, "vector_init(): received NULL ptr, not doing anything\n");
		return 1;
	}

	if (p < 0 || p >= (CHAR_BIT * sizeof v->data[0]))
		p = 0;
	v->max = 1 << p;
	v->n = 0;
	v->data = (int *) s_calloc((size_t) v->max, sizeof *v->data);

	return 0;
}

extern int
vector_append(struct vector *v, int a)
{
	int *t = NULL;

	if (v == NULL) {
		fprintf(stderr, "vector_append(): received NULL ptr, not doing anything\n");
		return 1;
	}

	if (v->max == 0)
		vector_init(v, 0);

	if (v->n + 1 > v->max) {
		t = (int *) realloc(v->data, sizeof *t * (v->max *= 2));
		if (!t) {
			fprintf(stderr, "vector_append(): failed to allocate %d bytes\n", v->max);
			return 1;
		} else {
			v->data = t;
		}
	}

	v->data[v->n++] = a;

	return 0;
}

extern int
vector_sort(struct vector *v, int (*cmpf)(const void *, const void *))
{
	if (v == NULL) {
		fprintf(stderr, "vector_sort(): received NULL ptr, not doing anything\n");
		return 1;
	}

	if (v->max > 0 && v->n > 1) {
		qsort(v->data, (size_t) v->n, sizeof *v->data, cmpf);
		return 0;
	} else {
		return 1;
	}
}

extern int
vector_cleanup(struct vector *v)
{
	if (v == NULL) {
		fprintf(stderr, "vector_cleanup(): received NULL ptr, not doing anything\n");
		return 1;
	}

	if (v->max > 0) {
		v->max = v->n = 0;
		free(v->data);
		v->data = NULL;
		return 0;
	} else {
		return 1;
	}
}
/* }}} */
/* }}} */

/* {{{ doubly-linked list */
struct dll_node {
	int x;
	int y;
	char *data;
	size_t _data_size;
	struct dll_node *prev, *next;
};
/* {{{ functions */
/*
 * This function inserts one node pointed to by 'ins' _after_ 'node'.
 */
extern struct dll_node *
dll_insert(struct dll_node *node, struct dll_node *ins)
{
	assert(node != NULL);
	if (ins == NULL) {
		debug_fprintf((stderr, "dll_insert(): ins is NULL, not doing anything\n"));
		return node;
	}

	if (node->next) {
		assert(node->next->prev == node);
		node->next->prev = ins;
	}
	ins->next = node->next;
	ins->prev = node;
	node->next = ins;
	return ins;
}

/*
 * This function extracts 'node' from a doubly-linked list and returns pointer
 * to that node, which pointers '->prev' and '->next' are not reset.
 *
 * If you really want to get rid of a node, call
 * 	free(dll_delete(unneeded_node));
 */
extern struct dll_node *
dll_delete(struct dll_node *node)
{
	if (!node) {
		debug_fprintf((stderr, "dll_delete(): received NULL ptr, wtf am i supposed to delete?\n"));
		return NULL;
	}

	if (node->prev) {
		assert(node->prev->next == node);
		node->prev->next = node->next;
	}
	if (node->next) {
		assert(node->next->prev == node);
		node->next->prev = node->prev;
	}

	return node;
}

/*
 * Merge-sort for doubly-linked list.
 *
 * TODO: work out the use of (*cmp)() function
 */
extern void
dll_mergesort(struct dll_node *head, int (*cmp)(const void *, const void *))
{
	struct dll_node *end, *mid;
	struct dll_node *sorted, *first, *second;
	struct dll_node *swap;

	if (head == NULL || head->next == NULL) /* lengths 0, 1 */
		return;

	end = mid = head;
	while (end && end->next && end->next->next) {
		end = end->next->next;
		mid = mid->next;
	}
	if (end && end->next) {
		end = end->next;
		mid = mid->next;
	}

	mid->prev->next = NULL;
	mid->prev = NULL;
	dll_mergesort(head, cmp);
	dll_mergesort(mid, cmp);

	if (cmp(head->data, mid->data) > 0) { /* this is the tricky part */
		char *t1;
		size_t t2;
		struct dll_node *t3;
		int t4;
#define SWAP_(a,b,t) do{(t)=(a),(a)=(b),(b)=(t);}while(0)
		if (head->next && mid->next)
			SWAP_(head->next->prev, mid->next->prev, t3);
		SWAP_(head->x, mid->x, t4);
		SWAP_(head->data, mid->data, t1);
		SWAP_(head->_data_size, mid->_data_size, t2);
		SWAP_(head->prev, mid->prev, t3);
		SWAP_(head->next, mid->next, t3);
#undef SWAP_
	}

	/*
	 * from now on using only ->prev and ->next pointers should suffice us
	 */
	first = head->next;
	if (first) first->prev = NULL;
	second = mid;

	sorted = head;
	sorted->next = NULL;
	assert(sorted->prev == NULL);

	while (first && second) {
		assert(sorted->next == NULL);

		/* TODO: un-copypaste this code (use 'swap' ptr) */
		if (cmp(first->data, second->data) < 0)
			swap = first;
		else
			swap = second;

		assert(swap->prev == NULL);

		sorted->next = swap;
		swap->prev = sorted;
		sorted = swap;

		swap = swap->next;
		if (swap) {
			assert(swap->prev == sorted);
			swap->prev->next = NULL;
			swap->prev = NULL;
		}
	}
	assert(sorted->next == NULL);
	if (first) {
		assert(first->prev == NULL);
		sorted->next = first;
		first->prev = sorted;
	}
	if (second) {
		assert(second->prev == NULL);
		sorted->next = second;
		second->prev = sorted;
	}
}
/* }}} */
/* }}} */

/* {{{ graph repr: adjlist w/ doubly-linked list */
enum vertex_st {
	VTX_ST_UNKN = 0,
	VTX_ST_OPEN = 1,
	VTX_ST_VISITED = 2
};

struct adjlist_dll {
	struct dll_node *head;
	struct dll_node *tail;
	size_t _list_len;

	enum vertex_st state;
	short color;
	int distance; /* int */
	int prev; /* index */
	int low; /* >= 1 unless unintialized */
	int fwd_num, bk_num; /* >= 1 unless uninitialized */
};
/* {{{ functions */
extern void
adjl_dll_connect(struct adjlist_dll *node, const int conid, const int edgeid)
{
	struct dll_node *Wilson;

	Wilson = (struct dll_node *) s_calloc(1, sizeof *Wilson);
	Wilson->x = conid;
	Wilson->y = edgeid;
	Wilson->prev = Wilson->next = NULL;

	if (node->head == NULL) {
		assert(node->tail == NULL);
		node->head = node->tail = Wilson;
		node->_list_len = 1;
	} else {
		dll_insert(node->tail, Wilson);
		node->_list_len++;
	}
}

extern void
adjl_dll_cleanup(struct adjlist_dll *al)
{
	struct dll_node *nx = al->head, *pr = al->head;

	while (nx) {
		pr = nx;
		nx = nx->next;
		free(pr);
	}
	al->_list_len = 0;
	al->head = al->tail = NULL;
}
/* }}} */
/* }}} */

int
numcmp(const void *p1, const void *p2)
{
	if (* (const int *) p1 < * (const int *) p2)
		return -1;
	else if (* (const int *) p1 == * (const int *) p2)
		return 0;
	else
		return 1;
}

int
dfs_find_bridges(struct adjlist_dll *al, const int s, const int anc,
		struct vector *br, int *fwd_id)
{
	struct dll_node *nd = al[s].head;

	debug_fprintf((stderr, "%d:entering node %d, ancestor %d\n",
				s + 1, s + 1, anc + 1));
	if (al[s].state != VTX_ST_UNKN) {
		debug_fprintf((stderr, "%d:al[s].state != VTX_ST_UNKN, what are we doing here?\n",
					s + 1));
		return 0;
	}
	al[s].state = VTX_ST_OPEN;
	al[s].prev = anc;
	al[s].fwd_num = ++*fwd_id;
	al[s].low = al[s].fwd_num;

	while (nd) {
		if (nd->x == anc) {
			nd = nd->next;
			continue;
		}

		if (al[nd->x].fwd_num == 0) {
			/* tree edge */
			dfs_find_bridges(al, nd->x, s, br, fwd_id);
			debug_fprintf((stderr, "%d:al[%d].low(%d) = ",
						s + 1, s + 1, al[s].low));
			al[s].low = MIN(al[s].low, al[nd->x].low);
			debug_fprintf((stderr, "%d\n", al[s].low));

			if (al[nd->x].low == al[nd->x].fwd_num) {
				debug_fprintf((stderr, "%d:al[%d].low == al[%d].fwd_num == %d",
							s + 1, nd->x + 1, nd->x + 1, al[nd->x].low));
				debug_fprintf((stderr, " , adding edge (%d, %d) [%d] to the answer\n",
							s + 1, nd->x + 1, nd->y));
				vector_append(br, nd->y);
			}
		} else {
			/* back edge */
			debug_fprintf((stderr, "%d:found cycle (%d, %d)\n",
						s + 1, s + 1, nd->x + 1));
			debug_fprintf((stderr, "%d:al[%d].low(%d) = ",
						s + 1, s + 1, al[s].low));
			al[s].low = MIN(al[s].low, al[nd->x].fwd_num);
			debug_fprintf((stderr, "%d\n", al[s].low));
			debug_fprintf((stderr, "%d:al[%d].low=%d, al[%d].fwd_num=%d\n",
						s + 1, nd->x + 1, al[nd->x].low, nd->x + 1,
						al[nd->x].fwd_num));
		}

		nd = nd->next;
	}

	debug_fprintf((stderr, "%d:leaving node %d\n", s + 1, s + 1));
	al[s].state = VTX_ST_VISITED;

	return 0;
}

int
main(void)
{
	struct adjlist_dll *al;
	int i, n, m, a, b;
	struct vector bridges;
	int fwd_id = 0;

	scanf("%d%d", &n, &m);
	al = (adjlist_dll *) calloc(n, sizeof *al);
	vector_init(&bridges, 7);
	for (i = 0; i < m; i++) {
		scanf("%d%d", &a, &b);
		--a; --b;
		adjl_dll_connect(al + a, b, i + 1);
		adjl_dll_connect(al + b, a, i + 1);
	}

	dfs_find_bridges(al, 0, -1, &bridges, &fwd_id);

	vector_sort(&bridges, numcmp);
	printf("%d\n", bridges.n);
	for (i = 0; i < bridges.n; i++)
		printf("%d ", bridges.data[i]);
	fputc('\n', stdout);

#ifdef D
	for (i = 0; i < n; i++) {
		fprintf(stderr, "al[%3d] = { low = %3d, fwd_num = %3d, etc. }\n",
				i + 1, al[i].low, al[i].fwd_num);
	}
#endif

	for (i = 0; i < n; i++) adjl_dll_cleanup(al + i);
	free(al);
	vector_cleanup(&bridges);
	return 0;
}
